#include "SharedMemoryIPC.h"
SharedMemoryIPC *SharedMemoryIPC::readerInstance = nullptr;
SharedMemoryIPC *SharedMemoryIPC::writerInstance = nullptr;
std::mutex SharedMemoryIPC::readerMutex;
std::mutex SharedMemoryIPC::writerMutex;

// 获取读单例（线程安全）
SharedMemoryIPC &SharedMemoryIPC::getReaderInstance(key_t msg_key, key_t shm_key, key_t sem_key)
{
    if (!readerInstance)
    {
        std::lock_guard<std::mutex> lock(readerMutex);
        if (!readerInstance)
        {
            readerInstance = new SharedMemoryIPC(READER, msg_key, shm_key, sem_key);
        }
    }
    return *readerInstance;
}

// 获取写单例（线程安全）
SharedMemoryIPC &SharedMemoryIPC::getWriterInstance(key_t msg_key, key_t shm_key, key_t sem_key)
{
    if (!writerInstance)
    {
        std::lock_guard<std::mutex> lock(writerMutex);
        if (!writerInstance)
        {
            writerInstance = new SharedMemoryIPC(WRITER, msg_key, shm_key, sem_key);
        }
    }
    return *writerInstance;
}
SharedMemoryIPC::SharedMemoryIPC(Mode mode, key_t msg_key, key_t shm_key, key_t sem_key)
    : current_mode(mode), msg_key_(msg_key), shm_key_(shm_key), sem_key_(sem_key)
{
    init_ipc();
}

SharedMemoryIPC::~SharedMemoryIPC()
{
}

void SharedMemoryIPC::init_ipc()
{

    if (current_mode == WRITER)
    {

        //int old_shmid = shmget(shm_key_, 0, 0666);
        // if (old_shmid != -1)
        // {
        //     shmctl(old_shmid, IPC_RMID, NULL); // 删除
        //     std::cout << "Removed old shared memory segment (size mismatch)" << std::endl;
        // }

        umask(0);
        int size = sizeof(int) * BLOCK_NUM + BLOCK_SIZE * BLOCK_NUM;
        std::cout << "DEBUG: shm_key_=0x" << std::hex << shm_key_
                  << ", size=" << std::dec << size << std::endl;

        std::cout << "Shared memory size: " << size << std::endl;
        // 初始化消息队列
        msgid = msgget(msg_key_, IPC_CREAT | 0666);
        if (msgid < 0)
        {
            perror("msgget");
            exit(1);
        }
        // 初始化共享内存
        shmid = shmget(shm_key_, size, IPC_CREAT | 0666);
        cout<<"后置服务器开辟的写共享内存shmid="<<shmid<<endl;
        cout<<"shmid="<<shmid<<endl;
        if (shmid < 0)
        {
            perror("写 shmget");
            exit(1);
        }
        // 共享内存首地址
        void *shmaddr = shmat(shmid, NULL, 0);
        bzero(shmaddr, size);
        shmdt(shmaddr);

        // 初始化信号量
        semid = sem.sem_create(sem_key_, 1);
        if (semid < 0)
        {
            perror("semget");
            exit(1);
        }
        sem.sem_setval(semid, 0, 1);
    }
    else
    {
        umask(0);
        int size = sizeof(int) * BLOCK_NUM + BLOCK_SIZE * BLOCK_NUM;
        std::cout << "Shared memory size: " << size << std::endl;
        // 初始化消息队列
        msgid = msgget(msg_key_, IPC_CREAT | 0666);
        if (msgid < 0)
        {
            perror("msgget");
            exit(1);
        }
        // 初始化共享内存
        shmid = shmget(shm_key_, size,  0666);
        cout<<"shm_key_="<<shm_key_<<endl;
        cout<<"shmid="<<shmid<<endl;
        if (shmid < 0)
        {
            perror("读 shmget");
            exit(1);
        }
        // //共享内存首地址
        // void *shmaddr=shmat(shmid,NULL,0);
        // bzero(shmaddr,size);
        // shmdt(shmaddr);

        // 初始化信号量
        semid = sem.sem_create(sem_key_, 1);
        if (semid < 0)
        {
            perror("semget");
            exit(1);
        }
        // sem_setval(semid,0,1);
    }
}

int SharedMemoryIPC::write_shm(char *data)
{
    // int arr[BLOCK_NUM]={0};
    int index = -1;

    sem.sem_p(semid, 0);
    // 连接共享内存
    void *shmaddr = shmat(shmid, NULL, 0);
    {
        lock_guard<mutex> lock(mutex_);
        memcpy(arr, shmaddr, sizeof(arr));
        for (int i = 0; i < BLOCK_NUM; i++)
        {
            if (arr[i] == 0)
            {
                index = i;
                arr[index] = 1;
                memcpy(shmaddr + sizeof(int) * index, &arr[index], sizeof(int));
                break;
            }
        }
    }

    if (index == -1)
    {
        sem.sem_v(semid, 0);
        cout << "没有空闲数据块" << endl;
        sleep(1);
        return -1;
    }
    memcpy(shmaddr + sizeof(int) * BLOCK_NUM + index * BLOCK_SIZE, data, BLOCK_SIZE);
    sem.sem_v(semid, 0);
    cout << "写入共享内存数据len:" << " index=" << index << endl;

    msg = {0};
    msg.mtype = 1;
    sprintf(msg.mtext, "%d", index);
    int res = msgsnd(msgid, &msg, sizeof(MSG), 0);
    if (res == -1)
    {
        perror("msgsnd");
        exit(1);
    }
    else
    {
        cout << "发送消息成功" << endl;
    }
    return 0;
}

void SharedMemoryIPC::read_shm(char *data)
{
    msg = {0};
    arr[BLOCK_NUM] = {0};
    // 计算下标
    int index = -1;
    int res = msgrcv(msgid, &msg, sizeof(MSG), 1, 0);
    if (res < 0)
    {
        perror("msgrcv");
        exit(1);
    }
    index = atoi(msg.mtext);
    cout << "消息队列中读到的index:" << index << endl;
    // 从对应数据块里面读取数据
    sem.sem_p(semid, 0);
    void *shmadder = shmat(shmid, NULL, 0);
    memcpy(data, shmadder + index * BLOCK_SIZE + sizeof(int) * BLOCK_NUM, BLOCK_SIZE);
    bzero(shmadder + index * BLOCK_SIZE + sizeof(int) * BLOCK_NUM, BLOCK_SIZE);
    bzero(shmadder + sizeof(int) * index, sizeof(int));
    sem.sem_v(semid, 0);
    int fd=0;
    memcpy(&fd,data,sizeof(int));
    cout<<"后端从消息队列中读到的fd:"<<fd<<endl;
}
